package com.toplabs.unashu.interceptor;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.toplabs.unashu.annotation.CreateTime;
import com.toplabs.unashu.annotation.PrimaryKey;
import com.toplabs.unashu.annotation.UpdateTime;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 * @author toplabs
 * @since 2022/08/15
 * <p>This java file was created by toplabs in 2022/08/15.
 * The following is the description information about this file:</p>
 * <p>description: 自动填充拦截器</p>
 * 自定义 Mybatis 插件，自动设置 PrimaryKey、CreateTime 和 UpdateTime 的值。
 * 拦截 Update 操作(添加和修改)
 * 不能使用xml配置文件，因为会和其他Mybatis的配置冲突，因此添加 @Component
 */
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class AutoFillInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        // 获取 SQL 命令
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        // 获取参数
        Object parameter = invocation.getArgs()[1];
        log.debug("sql parameter, {}", parameter.toString());
        // 批量修改
        if (parameter instanceof MapperMethod.ParamMap) {
            Map<String, ?> param = (MapperMethod.ParamMap<?>) parameter;
            if (param.containsKey("collection")) {
                final List<?> collection = (List<?>) param.get("collection");
                collection.forEach(o -> parameterHandling(o, sqlCommandType));
            } else {
                parameterHandling(parameter, sqlCommandType);
            }
        } else {
            parameterHandling(parameter, sqlCommandType);
        }
        return invocation.proceed();
    }

    private void setParameterValue(Field field, Object target, Object value, boolean isNonValue) {
        ReflectionUtils.makeAccessible(field);
        if (isNonValue) {
            if (ReflectionUtils.getField(field, target) == null) {
                ReflectionUtils.setField(field, target, value);
            }
        } else {
            ReflectionUtils.setField(field, target, value);
        }
    }

    private void parameterHandling(Object parameter, SqlCommandType sqlCommandType) {
        // 如果不是insert或update语句，直接return
        if (!(SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType))) {
            return;
        }
        // 获取私有成员变量
        Field[] declaredFields = parameter.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.isAnnotationPresent(UpdateTime.class)) {
                setParameterValue(field, parameter, DateUtil.date(), false);
            }
            if (SqlCommandType.INSERT.equals(sqlCommandType)) {
                // 只有在值为null进行自动填充
                if (field.getAnnotation(PrimaryKey.class) != null) {
                    setParameterValue(field, parameter, IdUtil.getSnowflakeNextId(), true);
                }
                if (field.getAnnotation(CreateTime.class) != null) {
                    setParameterValue(field, parameter, DateUtil.date(), true);
                }
            }
        }
    }
}
